package com.cis.fingerprint.core;

import com.cis.fingerprint.utils.ByteUtils;
import org.apache.commons.lang3.ArrayUtils;

public class PackageManager {

    /**
     * 包类型
     */
    public static final byte B_PID_COMMAND = 0x01;
    public static final byte B_PID_DATA = 0x02;
    public static final byte B_PID_RESPONSE = 0x07;
    public static final byte B_PID_LAST_DATA = 0x08;



    /**
     * 反馈码
     */
    //自定义
    public static final byte B_ACK_RET_UNKNOWN = -1;//未知错误.
    public static final byte B_ACK_RET_TIMEOUT = -2;//等待超时.
    public static final byte B_ACK_RET_PARAMETER_ERR = -3;//参数错误.

    //下位机应答码
    public static final byte B_ACK_RET_OK = 0X00;//成功
    public static final byte B_ACK_RET_INVALID_PACKET = 0X01;//无效数据包.
    public static final byte B_ACK_RET_NO_FINGER = 0X02;//传感器未检测到手指.


    //相关
    public static final byte B_ACK_RET_PID_PST = 0X06;
    public static final byte B_ACK_RET_TYPE_PST = 0X09;
    public static final byte B_ACK_RET_PACKAGE_PRE_CONTENT_SIZE = 0X09;
    public static final int N_RESPONSE_SIZE = 12;//返回类型包大小

    //通讯包参数
    public static final int PACKAGE_HEAD_SIZE = 2; //包头，占用字节数2，固定值（0xEF01）
    public static final int PACKAGE_ADD_SIZE = 4; //模块地址，占用字节数4，默认值（0xFFFFFFFF）
    public static final int PACKAGE_TYPE_SIZE = 1; //包类型，占用字节数1，0x01：指令包，由上位机向本模块发送
                                                               //0x02：普通数据包，后续至少再接若干个普通数据包和一个最后数据包
                                                               //0x08：最后数据包，作为本次数据发送的最后一个数据包
                                                               //0x07：应答包，由本模组向上位机发送
    public static final int PACKAGE_LENGTH_SIZE = 2; //包长度，占用字节数2，内容与校验和占用的空间总字节长度

    public static final int PACKAGE_CHECK_SUM_SIZE = 2; //校验和，占用字节数2，从包类型到内容的每个字节的累加和


    /**
     * 构造通讯包
     *
     * @param bPID 包类型
     * @param barrContent 包内容
     * @return 通讯包
     */
    public static byte[] constructPackageData(byte bPID, byte[] barrContent){
        int nContentSize = barrContent.length;

        //通讯包字节长度 = 包头字节长度 + 模块地址字节长度 + 包类型字节长度 + 包长度字节长度 + 内容字节长度 + 校验和字节长度
        int nPackageSize =PACKAGE_HEAD_SIZE + PACKAGE_ADD_SIZE + PACKAGE_TYPE_SIZE
                +PACKAGE_LENGTH_SIZE + nContentSize + PACKAGE_CHECK_SUM_SIZE;

        byte[] barrPackage = new byte[nPackageSize];

        //包头 (0xEF01)
        barrPackage[0] = (byte)0xEF;
        barrPackage[1] = 0x01;
        //模块地址(0xFFFFFFFF)
        barrPackage[2] = (byte)0xFF;
        barrPackage[3] = (byte)0xFF;
        barrPackage[4] = (byte)0xFF;
        barrPackage[5] = (byte)0xFF;

        //包类型 0x01：指令包  0x02：普通数据包 0x08：最后数据包 0x07：应答包
        barrPackage[6] = bPID;

        //包长度 内容与校验和占用的空间总字节长度
        int nLength  = nContentSize + PACKAGE_LENGTH_SIZE;
        barrPackage[8] = (byte)(nLength & 0x000000FF);
        barrPackage[7] = (byte)((nLength & 0x0000FF00) >> 8);

        //包内容
        System.arraycopy(barrContent, 0, barrPackage, 9, barrContent.length);

        //校验位
        int nCheckSum = 0;
        for (int i = 6; i < nPackageSize - PACKAGE_CHECK_SUM_SIZE; i++) {
            nCheckSum += (barrPackage[i] & 0xFF);
        }

        barrPackage[nPackageSize -2] = (byte)((nCheckSum & 0x0000ff00) >> 8);
        barrPackage[nPackageSize -1] = (byte)(nCheckSum & 0x000000ff);

        return barrPackage;
    }

    /**
     * 解析接收的通讯包
     * @param bPackageReceived 通讯包
     * @return
     */
    public static byte analyzePackageReceived(byte[] bPackageReceived){
        byte bnRetResponse = -1;

        if (null == bPackageReceived || bPackageReceived.length <= 0){
            return bnRetResponse;
        }

        //校验位验证
        boolean bIsCheckSumEqual = false;

        //解析包类型
        byte bPID = bPackageReceived[B_ACK_RET_PID_PST];

        //校验位地址
        byte snCheckSumHigh = bPackageReceived[bPackageReceived.length - 2];
        byte snCheckSumLow = bPackageReceived[bPackageReceived.length - 1];

        int nCheckSumLocal = 0;

        //TODO 判断包头和地址

        //计算校验码
        for (int i = B_ACK_RET_PID_PST; i < bPackageReceived.length - 2; i++) {
            nCheckSumLocal += (int)(bPackageReceived[i] & 0xff);
        }

        int a = ((int)(snCheckSumHigh & 0xff) << 8) + (int)(snCheckSumLow & 0xff);

        if ((a & 0x0000ffff) == (nCheckSumLocal & 0x0000ffff)){
            bIsCheckSumEqual = true;
        }

        switch (bPID){
            case B_PID_RESPONSE: //应答包
                byte bACK = bPackageReceived[B_ACK_RET_TYPE_PST];
                if (bACK == B_ACK_RET_OK && !bIsCheckSumEqual){
                    //校验码验证失败
                    bnRetResponse = -2;
                }else{
                    bnRetResponse = bACK;
                }
                break;
            case B_PID_DATA: //数据包
            case B_PID_LAST_DATA: //最后数据包
                if (bIsCheckSumEqual){
                    bnRetResponse = B_ACK_RET_OK;
                }else{
                    bnRetResponse = -2;
                }
                break;
            default:
                bnRetResponse = -3;
        }
        return bnRetResponse;
    }

    /**
     * 获取数据包大小
     *
     * @param barrPackagePreContentReceive
     * @return
     */
   public static int getTheSizeOfNextContent(byte[] barrPackagePreContentReceive){
        int sizeOfNextContent = 0;

        if (null == barrPackagePreContentReceive){
            return sizeOfNextContent;
        }

        byte[] barrPackageHead = ArrayUtils.subarray(barrPackagePreContentReceive, 0, 6);

        String strPackage = ByteUtils.byteArrayToHexString(barrPackageHead);

        if (strPackage.equals("EF01FFFFFFFF")){
            int nSizeOfPreContent = barrPackagePreContentReceive.length;

            int nSizeHigh = (barrPackagePreContentReceive[nSizeOfPreContent - 2] & 0xff);
            int nSizeLow = (barrPackagePreContentReceive[nSizeOfPreContent -1] &0xff);

            sizeOfNextContent = nSizeHigh * 256 + nSizeLow;
        }

        return sizeOfNextContent;


   }


}



































